#include "Driver_SPI.h"

/**
 * @brief 初始化SPI, 带DMA
 *
 */
void Driver_SPI_InitByDMA(void)
{
    /* -------------------- SPI初始化 -------------------- */
    FL_SPI_InitTypeDef spiInit = { 0 };

    spiInit.transferMode  = FL_SPI_TRANSFER_MODE_FULL_DUPLEX; // 全双工
    spiInit.mode          = FL_SPI_WORK_MODE_MASTER;          // 主模式
    spiInit.dataWidth     = FL_SPI_DATA_WIDTH_8B;             // 数据宽度8bit
    spiInit.clockPolarity = FL_SPI_POLARITY_NORMAL;           // 时钟极性：空闲时钟为低电平
    spiInit.clockPhase    = FL_SPI_PHASE_EDGE1;               // 第一个跳变沿开始采样
    spiInit.softControl   = FL_DISABLE;                       // 主模式下NSS不需要使能
    spiInit.baudRate      = FL_SPI_BAUDRATE_DIV4;             // 8分频
    spiInit.bitOrder      = FL_SPI_BIT_ORDER_MSB_FIRST;       // 数据高位先行
    FL_SPI_Init(SPI1, &spiInit);

    FL_SPI_SetHardwareSSNMode(SPI1, FL_SPI_HARDWARE_SSN_KEEP_LOW);

    /* -------------------- DMA初始化, 均未配置循环模式 -------------------- */
    FL_DMA_InitTypeDef dmaInit = { 0 };

    /* RX配置 */
    dmaInit.periphAddress        = FL_DMA_PERIPHERAL_FUNCTION1; // DMA外设映射地址, 用户手册映射表8个请求源,
                                                                // 从上往下第几个就是FUNCTIONx
    dmaInit.direction            = FL_DMA_DIR_PERIPHERAL_TO_RAM; // DMA传输方向, 因为是接收所以是外设 to RAM
    dmaInit.memoryAddressIncMode = FL_DMA_MEMORY_INC_MODE_INCREASE; // RAM地址自增
    dmaInit.dataSize             = FL_DMA_BANDWIDTH_8B;             // 数据位宽
    dmaInit.priority             = FL_DMA_PRIORITY_HIGH;            // 通道优先级-> 高
    dmaInit.circMode             = FL_DISABLE;
    FL_DMA_Init(DMA, &dmaInit, FL_DMA_CHANNEL_3);

    /* TX配置 */
    dmaInit.periphAddress = FL_DMA_PERIPHERAL_FUNCTION2;
    dmaInit.circMode      = FL_ENABLE;                    // 使能循环模式, 这样阀能一直保持设置的状态
    dmaInit.direction     = FL_DMA_DIR_RAM_TO_PERIPHERAL; // DMA传输方向, 因为是发送所以是RAM to 外设
    FL_DMA_Init(DMA, &dmaInit, FL_DMA_CHANNEL_4);

    /* GPIO配置 */
    FL_GPIO_InitTypeDef gpioInit = { 0 };

    /* PD2->SPI_SSN, PD3->SPI_SCK, PD5->SPI_MOSI */
    gpioInit.pin          = FL_GPIO_PIN_2 | FL_GPIO_PIN_3 | FL_GPIO_PIN_5;
    gpioInit.mode         = FL_GPIO_MODE_DIGITAL;    // 数字模式
    gpioInit.outputType   = FL_GPIO_OUTPUT_PUSHPULL; // 推挽输出
    gpioInit.pull         = FL_DISABLE;              // 禁用上拉使能
    gpioInit.remapPin     = FL_DISABLE;              // 禁用复用
    gpioInit.analogSwitch = FL_DISABLE;              // 禁用模拟IO
    FL_GPIO_Init(GPIOD, &gpioInit);

    /* 595_EN */
    gpioInit.pin  = FL_GPIO_PIN_6;
    gpioInit.mode = FL_GPIO_MODE_OUTPUT;
    FL_GPIO_Init(GPIOD, &gpioInit);
    FL_GPIO_ResetOutputPin(GPIOD, FL_GPIO_PIN_6);

    FL_DMA_Enable(DMA);
}

/**
 * @brief 通过DMA发送数据
 *
 * @param srcAddr   源地址
 * @param len       数据长度, 要减一
 */
void Driver_SPI_SendDataByDMA(uint32_t srcAddr, uint16_t len)
{
    /* 1. 清空SPI发送缓冲区 */
    FL_SPI_ClearTXBuff(SPI1); // 防止之前的数据影响传输

    /* 2. 配置DMA传输参数 */
    FL_DMA_WriteTransmissionSize(DMA, len - 1, FL_DMA_CHANNEL_4); // 设置传输长度, 注意要-1
    FL_DMA_WriteMemoryAddress(DMA, srcAddr, FL_DMA_CHANNEL_4);    // 设置源地址
    FL_DMA_ClearFlag_TransferComplete(DMA, FL_DMA_CHANNEL_4);     // 清除传输完成标志, 为新的传输做准备

    /* 3. 开始传输 */
    FL_DMA_EnableChannel(DMA, FL_DMA_CHANNEL_4); // 使能DMA通道, 开始传输
}

/**
 * @brief 使能SPI的DMA通道
 *
 * @param channel DMA通道号
 */
void Driver_SPI_EnableDMAChannel(uint32_t channel) { FL_DMA_EnableChannel(DMA, channel); }

/**
 * @brief 失能SPI的DMA通道
 *
 * @param channel DMA通道号
 */
void Driver_SPI_DisableDMAChannel(uint32_t channel) { FL_DMA_DisableChannel(DMA, channel); }
